home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
eulisp
/
mpfeel.lha
/
MPFeel
/
error.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-06
|
21KB
|
724 lines
/* ******************************************************************** */
/* error.c Copyright (C) Codemist and University of Bath 1989 */
/* */
/* Error and Signal handling */
/* ******************************************************************** */
/*
* Change Log:
* Version 1, April 1989
* Added names of the defined conditions - JPff
* Version 2, May 1989
* Amalgamated with section condition.c for sanity
* Version 3, May 1989
* Updated for new ideas on handlers/restarts - RJB
* Integrated conditions into the object system - KJP
* Version 4, June 1990
* Rewrote handlers and signals correctly - KJP
* - with-handler special
* - generally rearranged
*/
#include <stdio.h>
#include <string.h>
#include "defs.h"
#include "structs.h"
#include "funcalls.h"
#include "global.h"
#include "error.h"
#include "bootstrap.h"
#include "slots.h"
#include "class.h"
#include "symboot.h"
#include "modules.h"
#include "specials.h"
#include "modboot.h"
#include "ngenerics.h"
#include "calls.h"
#include "state.h"
#define N_SLOTS_IN_CONDITION 2
/* The error system classes... */
LispObject Condition_Class;
LispObject Default_Condition;
/* Array for pre-defind conditions... */
LispObject defined_conditions; /* a vector of junk */
extern LispObject unbound;
/*
* Conditions...
* Includes generation and defined slot access...
*/
/* Predicate... */
EUFUN_1( Fn_conditionp, form)
{
return (is_condition(form) ? lisptrue : nil);
}
EUFUN_CLOSE
/* Generator... */
EUFUN_2( Fn_make_condition, class, initlist)
{
LispObject ans;
EUCALLSET_2(ans, Fn_subclassp, classof(class),Condition_Class);
if (ans==nil)
CallError(stackbase, "make-condition: non condition class",
ARG_0(stackbase),NONCONTINUABLE);
return(Gf_make_instance(stackbase));
}
EUFUN_CLOSE
/*
* Built in condition slot accessors...
*/
EUFUN_1( Fn_condition_name, cond)
{
if (!is_condition(cond))
CallError(stackbase,"condition-name: not a condition",cond,NONCONTINUABLE);
return classof(cond)->CLASS.name;
}
EUFUN_CLOSE
EUFUN_1( Fn_condition_message, cond)
{
if (!is_condition(cond))
CallError(stackbase,
"condition-message: not a condition",cond,NONCONTINUABLE);
return(condition_message(cond));
}
EUFUN_CLOSE
EUFUN_1( Fn_condition_error_value, cond)
{
if (!is_condition(cond))
CallError(stackbase,
"condition-error-value: not a condition",cond,NONCONTINUABLE);
return(condition_error_value(cond));
}
EUFUN_CLOSE
/*
* Signals and Handlers...
*/
/* Heap collapse... */
void signal_heap_failure(LispObject *stackbase, int type)
{
extern LispObject Fn_abort_thread(LispObject*);
extern LispObject interpreter_thread;
extern LispObject read_eval_print_continue;
fprintf(StdErr->STREAM.handle,
"\nTrapping heap exhaustion condition on type %x\n\n",type);
#ifndef MACHINE_ANY
if (CURRENT_THREAD() == CAR(interpreter_thread)) {
fprintf(StdErr->STREAM.handle,
"Calculation abandoned - returning to top level...\n\n");
call_continue(stackbase,CAR(read_eval_print_continue),lisptrue);
}
fprintf(StdErr->STREAM.handle,
"Thread aborting - wait for other failures...\n\n");
(void) Fn_abort_thread(stackbase);
#else
fprintf(StdErr->STREAM.handle,
"Calculation abandoned - returning to top level...\n\n");
call_continue(stackbase,CAR(read_eval_print_continue),lisptrue);
#endif
}
/* Prompt string... */
#define MAX_PROMPT_LENGTH (1024)
char current_prompt_string[MAX_PROMPT_LENGTH];
/* Default signal handling... */
static LispObject sym_pling_backtrace;
static LispObject sym_pling_b;
static LispObject sym_pling_quickie;
static LispObject sym_pling_q;
LispObject sym_pling_exit;
LispObject sym_pling_root;
extern LispObject Gf_generic_write(LispObject*);
void condition_handler(LispObject *stackbase, LispObject cond,LispObject cont)
{
extern
SYSTEM_THREAD_SPECIFIC_DECLARATION(int,system_scheduler_number);
extern
LispObject Gf_generic_prin(LispObject*);
extern
void module_eval_backtrace(LispObject *);
extern
void quickie_module_eval_backtrace(LispObject *);
extern
LispObject get_history_form(LispObject);
extern
void put_history_form(LispObject*, LispObject);
extern
int get_history_count(void);
LispObject *stacktop = stackbase;
LispObject form,value;
LispObject *gc_index = GC_STACK_POINTER();
while (TRUE) {
sprintf(current_prompt_string,"eulisp-handler:%x:%s!%d> ",
SYSTEM_THREAD_SPECIFIC_VALUE(system_scheduler_number),
SYSTEM_GLOBAL_VALUE(current_interactive_module)
->I_MODULE.name->SYMBOL.pname,
get_history_count());
/*
fprintf(StdErr->STREAM.handle,"eulisp-handler:%x:",
SYSTEM_THREAD_SPECIFIC_VALUE(system_scheduler_number));
EUCALL_2(Gf_generic_prin,
SYSTEM_GLOBAL_VALUE(current_interactive_module)->I_MODULE.name,
StdErr);
fprintf(StdErr->STREAM.handle,"!%d> ",get_history_count());
*/
#ifndef GNUREADLINE
fprintf(StdErr->STREAM.handle,"%s",current_prompt_string);
#endif
EUCALLSET_1(form, Fn_read, StdIn);
form = get_history_form(form);
put_history_form(stacktop, form);
if (form == sym_pling_exit || form == q_eof) return;
if (form == sym_pling_root) {
SYSTEM_GLOBAL_VALUE(current_interactive_module) =
get_module(stacktop,sym_root);
value = nil;
}
else if (form == sym_pling_backtrace || form == sym_pling_b) {
module_eval_backtrace(stacktop);
value = nil;
}
else if (form == sym_pling_quickie || form == sym_pling_q) {
quickie_module_eval_backtrace(stacktop);
value = nil;
}
else
EUCALLSET_2(value,process_top_level_form,
SYSTEM_GLOBAL_VALUE(current_interactive_module),
form);
fprintf(StdErr->STREAM.handle,"eulisp-handler:%x:",
SYSTEM_THREAD_SPECIFIC_VALUE(system_scheduler_number));
STACK_TMP(value);
EUCALL_2(Gf_generic_prin, SYSTEM_GLOBAL_VALUE(current_interactive_module)
->I_MODULE.name,StdErr);
fprintf(StdErr->STREAM.handle,"!%d< ",get_history_count()-1);
UNSTACK_TMP(value);
EUCALL_2(Gf_generic_write,value,StdErr);
fprintf(StdErr->STREAM.handle,"\n\n");
}
}
LispObject function_bootstrap_handler;
EUFUN_2( Fn_bootstrap_handler, cond, cont)
{
LispObject slots;
/* Check for dumb errors... */
if (!is_condition(cond))
CallError(stackbase,
"Default Handler not given a condition",cond,NONCONTINUABLE);
if (!is_continue(cont) && cont != nil)
CallError(stackbase,"Invalid continuation in default handler",cont,
NONCONTINUABLE);
/* Now, display error message... */
fprintf(stderr,"\nCompiled Elvira initialisation code error!!!\n");
fprintf(stderr,"\nTrapping unhandled ");
if (cont == nil)
fprintf(stderr,"non-continuable \"");
else
fprintf(stderr,"continuable \"");
fprintf(stderr,"error\"");
fprintf(stderr,"Check for initcode module --- It is needed\n");
system_lisp_exit(1);
return(nil); /* dummy return */
}
EUFUN_CLOSE
LispObject function_default_handler;
EUFUN_2( Fn_default_handler, cond, cont)
{
LispObject slots;
/* Check for dumb errors... */
if (!is_condition(cond))
CallError(stackbase,
"Default Handler not given a condition",cond,NONCONTINUABLE);
if (!is_continue(cont) && cont != nil)
CallError(stackbase,"Invalid continuation in default handler",cont,
NONCONTINUABLE);
/* Now, display error message... */
/* Should check if it's a heap error... */
fprintf(stderr,"\nTrapping unhandled ");
if (cont == nil)
fprintf(stderr,"non-continuable \"");
else
fprintf(stderr,"continuable \"");
EUCALL_2(Gf_generic_write,classof(cond)->CLASS.name,StdErr);
fprintf(stderr,"\"\n\n");
cond = ARG_0(stackbase);
if (condition_message(cond) != nil) {
fprintf(stderr,"message: ");
EUCALL_2(Gf_generic_write,condition_message(cond),StdErr);
fprintf(stderr,"\n");
cond = ARG_0(stackbase);
}
if (condition_error_value(cond) != unbound) {
fprintf(stderr,"error-value: ");
EUCALL_2(Gf_generic_write,condition_error_value(cond),StdErr);
fprintf(stderr,"\n");
cond = ARG_0(stackbase);
}
/* Display the slot contents with names */
if (cond->CLASS.slot_table != nil) {
EUCALLSET_1(slots, Fn_class_slot_descriptions,classof(cond));
while (slots != nil) {
extern LispObject generic_slot_value_using_slot_description;
LispObject xx;
LispObject desc = CAR(slots);
slots = CDR(slots);
STACK_TMP(slots); STACK_TMP(desc);
EUCALLSET_1(xx, Fn_slot_description_name, desc);
EUCALL_2(Gf_generic_write, xx,StdErr);
fprintf(stderr,": ");
UNSTACK_TMP(desc);
cond = ARG_0(stackbase);
xx = generic_apply_2(stacktop,
generic_slot_value_using_slot_description,
cond, desc);
EUCALL_2(Gf_generic_write,xx,StdErr);
fprintf(stderr,"\n");
UNSTACK_TMP(slots);
}
}
fprintf(StdErr->STREAM.handle,"\n");
fflush(StdIn->STREAM.handle);
{
extern void module_eval_backtrace(LispObject *);
extern LispObject Fn_abort_thread(LispObject *);
extern LispObject read_eval_print_continue;
extern LispObject interpreter_thread;
extern void call_continuation(LispObject*,LispObject,LispObject);
/* Go for auto-backtrace on weird threads */
cond = ARG_0(stackbase);
cont = ARG_1(stackbase);
if (CURRENT_THREAD() == CAR(interpreter_thread)) {
fprintf(StdErr->STREAM.handle,"Entering condition handler...\n\n");
condition_handler(stacktop,cond,cont);
fprintf(StdErr->STREAM.handle,"\nReturning to top level...\n\n");
call_continuation(stacktop,CAR(read_eval_print_continue),nil);
}
#ifndef MACHINE_ANY
fprintf(StdErr->STREAM.handle,"ABORTING THREAD: ");
EUCALL_2(Gf_generic_write,CURRENT_THREAD(),StdErr);
fprintf(StdErr->STREAM.handle,"\n\nBacktrace follows...\n");
module_eval_backtrace(stacktop);
fprintf(StdErr->STREAM.handle,"Thread aborted.\n\n");
(void) Fn_abort_thread(stacktop);
#endif
}
return(nil); /* dummy return */
}
EUFUN_CLOSE
/* User signal function... */
EUFUN_2( Fn_signal, cond, cont)
{
LispObject stack;
if (cont != nil && !is_continue(cont))
CallError(stackbase,"signal: non continuation",cont,NONCONTINUABLE);
if (!is_condition(cond))
CallError(stackbase,"signal: not a condition",cond,NONCONTINUABLE);
/* OK, grab a handler and do the business... */
/* Here be strangeness - handlers are executed in the handler environment
of their establishment => (I think) just decrementing the handler stack
as we run along - continuations will re-instate, but keep a copy for
GC safety... */
stack = HANDLER_STACK();
STACK_TMP(stack);
while (is_cons(HANDLER_STACK())) {
LispObject handle;
handle = CAR(HANDLER_STACK());
HANDLER_STACK() = CDR(HANDLER_STACK());
/* Need this 'cos apply allocates... */
if (handle == function_default_handler)
EUCALL_2(Fn_default_handler,cond,cont);
else
EUCALL_3(apply2,handle,cond,cont);
cond = ARG_0(stackbase);
cont = ARG_1(stackbase);
/* Back here means try again... */
}
/* Ack! No handler accepted!! */
UNSTACK_TMP(stack);
HANDLER_STACK() = stack;
return(cond);
}
EUFUN_CLOSE
/*
* Internally used error handling and signalling...
*/
/* Signal condition i with message and one value... */
/* Emergency heap condition... */
LispObject condition_heap_exhausted;
void signal_message(LispObject *stackbase, int i,char *message,LispObject val)
{
LispObject cond_class;
LispObject cond;
LispObject *stacktop = stackbase;
STACK_TMP(val);
/* Special case if out of heap... */
if (i == HEAP_EXHAUSTED) {
cond = condition_heap_exhausted;
fprintf(StdErr->STREAM.handle,"Heap wimped out!! Rats.\n");
system_lisp_exit(1);
}
else {
cond_class = vref(defined_conditions,i)->SYMBOL.lvalue;
cond = (LispObject) allocate_instance(stacktop,cond_class);
}
STACK_TMP(cond);
condition_message(cond) =
(LispObject) allocate_string(stacktop,message,strlen(message));
UNSTACK_TMP(cond);
UNSTACK_TMP(val);
condition_error_value(cond) = val;
STACK_TMP(cond);
EUCALL_2(Fn_signal,cond,nil);
UNSTACK_TMP(cond);
/* Returned => call default... */
EUCALL_2(Fn_default_handler,cond,nil);
/* Returned means deep trouble... */
fprintf(stderr,"INTERNAL ERROR: signal returned on internal call\n");
fprintf(stderr,"Message was: '%s'\n",message); fflush(stderr);
system_lisp_exit(1);
}
LispObject CallError(LispObject *stackbase, char *format,LispObject x,int type)
{
IGNORE(type);
signal_message(stackbase, INTERNAL_ERROR,format,x);
return(nil);
}
EUFUN_3( Fn_cerror, message, cond, args)
{
LispObject cont,val;
cont = (LispObject) allocate_continue(stackbase);
if (set_continue(stacktop,cont)) return(cont->CONTINUE.value);
STACK_TMP(cont);
message = ARG_0(stackbase);
args = ARG_2(stackbase);
EUCALLSET_2(message, Fn_cons, message, args);
EUCALLSET_2(message, Fn_cons, sym_message, message);
cond = ARG_1(stackbase);
EUCALLSET_2(message, Fn_make_condition, cond, message);
UNSTACK_TMP(cont);
EUCALLSET_2(val, Fn_signal, message, cont);
call_continue(stacktop,cont,val);
return(val);
}
EUFUN_CLOSE
EUFUN_3( Fn_error, message, cond, args)
{
LispObject val;
EUCALLSET_2(message, Fn_cons, message, args);
EUCALLSET_2(message, Fn_cons, sym_message, message);
cond = ARG_1(stackbase);
EUCALLSET_2(message, Fn_make_condition, cond, message);
EUCALLSET_2(val, Fn_signal, message, nil);
return(val);
}
EUFUN_CLOSE
/* *************************************************************** */
/* Initialisation of this section */
/* *************************************************************** */
#define ERRORS_ENTRIES 10
MODULE Module_errors;
LispObject Module_errors_values[ERRORS_ENTRIES];
void initialise_error(LispObject *stacktop)
{
static char* inits[] = {
"Internal-Error", /* INTERNAL_ERROR */
"unbound-lexical-variable", /* UNBOUND_LEXICAL_VARIABLE */
"unbound-dynamic-variable", /* UNBOUND_DYNAMIC_VARIABLE */
"invalid-operator", /* INVALID_OPERATOR */
"no-update-function", /* NO_UPDATE_FUNCTION */
"immutable-binding", /* IMMUTABLE_BINDING */
"no-block-for-return", /* NO_BLOCK_FOR_RETURN */
"no-catch-for-throw", /* NO_CATCH_FOR_THROW */
"clock-tick", /* CLOCK_TICK */
"dead-continuation", /* DEAD_CONTINUATION */
"dead-thread", /* DEAD_THREAD */
"thread-overflow", /* THREAD_OVERFLOW */
"thread-underflow", /* THREAD_UNDERFLOW */
"cannot-make-array", /* CANNOT_MAKE_ARRAY */
"cannot-make-character", /* CANNOT_MAKE_CHARACTER */
"cannot-make-character_set", /* CANNOT_MAKE_CHARACTER_SET */
"cannot-make-float", /* CANNOT_MAKE_FLOAT */
"cannot-make-number", /* CANNOT_MAKE_NUMBER */
"cannot-make-pair", /* CANNOT_MAKE_PAIR */
"cannot-make-readtable", /* CANNOT_MAKE_READTABLE */
"cannot-make-stream", /* CANNOT_MAKE_STREAM */
"cannot-make-string", /* CANNOT_MAKE_STRING */
"cannot-make-symbol", /* CANNOT_MAKE_SYMBOL */
"cannot-make-table", /* CANNOT_MAKE_TABLE */
"cannot-make-thread", /* CANNOT_MAKE_THREAD */
"floating-overflow", /* FLOATING_OVERFLOW */
"floating-underflow", /* FLOATING_UNDERFLOW */
"integer-overflow", /* INTEGER_OVERFLOW */
"integer-underflow", /* INTEGER_UNDERFLOW */
"not-a-number", /* NOT_A_NUMBER */
"non-existent-file-or-device", /* NON_EXISTENT_FILE_OR_DEVICE */
"not-an-input-device", /* NOT_AN_INPUT_DEVICE */
"not-an-input-stream", /* NOT_AN_INPUT_STREAM */
"not-an-output-device", /* NOT_AN_OUTPUT_DEVICE */
"cannot-access-file", /* CANNOT_ACCESS_FILE */
"cannot-append-to-device", /* CANNOT_APPEND_TO_DEVICE */
"slot-unbound", /* SLOT_UNBOUND */
"slot-missing", /* SLOT_MISSING */
"bad-slot-index", /* BAD_SLOT_INDEX */
"no-lambda-list", /* NON_LAMBDA_LIST */
"non-allocatable-object", /* NON_ALLOCATABLE_OBJECT */
"no-applicable-method", /* NO_APPLICABLE_METHOD */
"non-congruent-lambda-lists", /* NON_CONGRUENT_LAMBDA_LISTS */
"cannot-make-vector", /* CANNOT_MAKE_VECTOR */
"heap-exhausted", /* HEAP_EXHAUSTED */
"uninitialized-lexical-variable", /* UNINITIALIZED_LEXICAL_VARIABLE */
"cannot-assign-variable", /* CANNOT_ASSIGN_VARIABLE */
"invalid-operands", /* INVALID_OPERANDS */
"immutable-location", /* IMMUTABLE_LOCATION */
"cannot-modify-empty-list", /* CANNOT_MODIFY_EMPTY_LIST */
"name-clash-in-module", /* NAME_CLASH_IN_MODULE */
"cannot-unquote-splice", /* CANNOT_UNQUOTE_SPLICE */
"semaphore-already-down", /* SEMAPHORE_ALREADY_DOWN */
"cannot-make-function", /* CANNOT_MAKE_FUNCTION */
"cannot-make-io-stream", /* CANNOT_MAKE_IO_STREAM */
"cannot-make-structure-class", /* CANNOT_MAKE_STRUCTURE_CLASS */
"cannot-open-path", /* CANNOT_OPEN_PATH */
"file-already-exists", /* FILE_ALREADY_EXISTS */
"inconsistent-open-options", /* INCONSISTENT_OPEN_OPTIONS */
"invalid-stream-position", /* INVALID_STREAM_POSITION */
"not-an-output-stream", /* NOT_AN_OUTPUT_STREAM */
"not-an-io-stream", /* NOT_AN_IO_STREAM */
"not-a-character-stream", /* NOT_A_CHARACTER_STREAM */
"not-a-binary-stream", /* NOT_A_BINARY_STREAM */
"not-a-positionable-stream", /* NOT_A_POSITIONABLE_STREAM */
"path-does-not-exist", /* PATH_DOES_NOT_EXIST */
"stream-not-open", /* STREAM_NOT_OPEN */
"non-congruent-lambda-list", /* NON_CONGRUENT_LAMBDA_LIST */
"no-next-method", /* NO_NEXT_METHOD */
"method-in-use", /* METHOD_IN_USE */
"invalid-return-continuation", /* invalid-return-continuation */
"invalid-throw-continuation", /* invalid-throw-continuation */
"cannot-make-tokeniser", /* cannot-make-tokeniser */
"bad-method-class", /* bad-method-class */
0
};
int i;
/* Initialise condition metaclass */
Condition_Class = (LispObject) allocate_class(stacktop,NULL);
add_root(&Condition_Class);
make_class( stacktop,
Condition_Class,
"condition-class",
Standard_Class,
Standard_Class, 0 );
Default_Condition = (LispObject) allocate_class(stacktop,NULL);
add_root(&Default_Condition);
make_class( stacktop,
Default_Condition,
"condition",
Condition_Class,
Object, N_SLOTS_IN_CONDITION);
defined_conditions=allocate_vector(stacktop,99);
add_root(&defined_conditions);
for (i=0; inits[i]; i++) {
LispObject cond_class;
vref(defined_conditions,i) = (LispObject) get_symbol(stacktop,inits[i]);
gen_class(stacktop,&cond_class,inits[i],Condition_Class,
Default_Condition);
vref(defined_conditions,i)->SYMBOL.lvalue = cond_class;
#if 0
cond_class = allocate_class(stacktop,Condition_Class);
cond_class->CLASS.superclasses = EUCALL_2(Fn_cons,Default_Condition,nil);
Default_Condition->CLASS.subclasses =
EUCALL_2(Fn_cons,cond_class,Default_Condition->CLASS.subclasses);
cond_class->CLASS.name = defined_conditions[i];
#endif
}
/* Rig heap failure condition... */
condition_heap_exhausted =
(LispObject)
allocate_instance(stacktop,
vref(defined_conditions,HEAP_EXHAUSTED)->SYMBOL.lvalue);
add_root(&condition_heap_exhausted);
sym_pling_backtrace = get_symbol(stacktop,"!backtrace");
add_root(&sym_pling_backtrace);
sym_pling_b = get_symbol(stacktop,"!b");
add_root(&sym_pling_b);
sym_pling_quickie = get_symbol(stacktop,"!quickie");
add_root(&sym_pling_quickie);
sym_pling_q = get_symbol(stacktop,"!q");
add_root(&sym_pling_q);
sym_pling_exit = get_symbol(stacktop,"!exit");
add_root(&sym_pling_exit);
sym_pling_root = get_symbol(stacktop,"!root");
add_root(&sym_pling_root);
open_module(stacktop,
&Module_errors,
Module_errors_values,
"errors",
ERRORS_ENTRIES);
(void) make_module_function(stacktop,"conditionp",Fn_conditionp,1);
(void) make_module_function(stacktop,"make-condition",Fn_make_condition,-2);
(void) make_module_function(stacktop,"condition-name",Fn_condition_name,1);
(void) make_module_function(stacktop,"condition-message",Fn_condition_message,1);
(void) make_module_function(stacktop,"condition-error-value",
Fn_condition_error_value,1);
(void) make_module_function(stacktop,"signal",Fn_signal,2);
function_bootstrap_handler
= make_unexported_module_function(stacktop,"bootstrap-handler",
Fn_bootstrap_handler,2);
add_root(&function_bootstrap_handler);
function_default_handler
= make_unexported_module_function(stacktop,"default-handler",Fn_default_handler,2);
add_root(&function_default_handler);
(void) make_module_function(stacktop,"error",Fn_error,-3);
(void) make_module_function(stacktop,"cerror",Fn_cerror,-3);
close_module();
}